package com.train.base.service.impl;

import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.entity.SysUserPost;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.SnowflakeIdWorker;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysPost;
import com.ruoyi.system.service.ISysDeptService;
import com.ruoyi.system.service.ISysPostService;
import com.ruoyi.system.service.ISysUserService;
import com.train.base.converter.AnswerConverter;
import com.train.base.domain.ExamQuestionBank;
import com.train.base.domain.ExamQuestionBankOption;
import com.train.base.domain.ExamSubjectKnowledgePoints;
import com.train.base.domain.ExamTestPaperModule;
import com.train.base.domain.TrainRecord;
import com.train.base.domain.TrainTestPaper;
import com.train.base.entity.bo.CommonTemplatesVo;
import com.train.base.entity.bo.PaperAnswer;
import com.train.base.entity.bo.Question;
import com.train.base.entity.bo.SpecialTrainProgress;
import com.train.base.entity.bo.SpecialTrainRule;
import com.train.base.entity.bo.StatisticalParam;
import com.train.base.entity.bo.SubjectAnalysis;
import com.train.base.entity.bo.TrainNum;
import com.train.base.entity.bo.UserRankingParam;
import com.train.base.entity.chart.LineChartData;
import com.train.base.entity.chart.SunriseChartData;
import com.train.base.enums.ResultTypeEnums;
import com.train.base.enums.TrainTestPaperStateEnums;
import com.train.base.enums.TrainTypeEnums;
import com.train.base.mapper.TrainMapper;
import com.train.base.service.IExamQuestionBankService;
import com.train.base.service.IExamSubjectKnowledgePointsService;
import com.train.base.service.IExamTestPaperModuleService;
import com.train.base.service.ITrainService;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.ruoyi.common.utils.PageUtils.startPage;
import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toMap;
import static java.util.stream.Collectors.toSet;

/**
 * 训练service
 */
@Service
public class TrainServiceImpl implements ITrainService {
    @Autowired
    private TrainMapper trainMapper;
    @Autowired
    private IExamTestPaperModuleService iExamTestPaperModuleService;
    @Autowired
    private ISysUserService iSysUserService;
    @Autowired
    private IExamQuestionBankService iExamQuestionBankService;
    @Autowired
    private IExamSubjectKnowledgePointsService examSubjectKnowledgePointsService;
    @Autowired
    private AnswerConverter answerConverter;
    @Autowired
    private ISysPostService sysPostService;
    @Autowired
    private ISysDeptService iSysDeptService;

    /**
     * 根据模板生成试卷
     *
     * @param moduleId
     * @return
     */
    @Override
    @Transactional
    public TrainTestPaper createTrainPaper(Long moduleId) {
        ExamTestPaperModule examTestPaperModule = iExamTestPaperModuleService.selectExamTestPaperModuleById(moduleId);
        if (Objects.isNull(examTestPaperModule)) {
            throw new BaseException("请先维护试卷模板");
        }
        // 创建试卷
        TrainTestPaper trainTestPaper = new TrainTestPaper();
        trainTestPaper.setId(SnowflakeIdWorker.build().nextId());
        trainTestPaper.setTestPaperModuleId(moduleId);
        trainTestPaper.setUserId(SecurityUtils.getUserId());
        trainTestPaper.setDeptId(examTestPaperModule.getDeptId());
        trainTestPaper.setState(TrainTestPaperStateEnums.WAIT_SUBMIT.getCode());
        trainTestPaper.setName(examTestPaperModule.getName() + LocalDate.now().format(DateTimeFormatter.ISO_LOCAL_DATE));
        // 获取试卷题目
        List<Question> questions = iExamTestPaperModuleService.createPaper(examTestPaperModule);
        QuestionToRecord(questions, TrainTypeEnums.SIMULATION.getCode(), examTestPaperModule.getPostId(), trainTestPaper);
        trainTestPaper.setQuestionNum((long) questions.size());
        trainTestPaper.setPostId(examTestPaperModule.getPostId());
        if (trainTestPaper.getPostLevelCode().compareTo(examTestPaperModule.getPostLevelCode()) < 0) {
            throw new BaseException("该用户能力级别不满足该模拟考试要求！");
        }
        trainMapper.insertTrainTestPaper(trainTestPaper);
        return trainTestPaper;
    }

    @Override
    public List<Question> listSpecial(SpecialTrainRule rule) {
        List<Question> questions = new ArrayList<>();
        List<ExamQuestionBank> examQuestionBanks = listBanksByRule(rule);
        examQuestionBanks.forEach(b -> {
            Question question = new Question();
            question.setType(b.getQuestionType());
            question.setQuestionId(b.getId());
            question.setContent(b.getContent());
            question.setRightKey(b.getRightKey());
            question.setAnalysis(b.getAnalysis());
            question.setExamQuestionBankOptionList(b.getExamQuestionBankOptionList());
            questions.add(question);
        });
        QuestionToRecord(questions, TrainTypeEnums.SPECIAL.getCode(), rule.getPostId(), null);
        return questions;
    }

    @Override
    public int insertTrainRecord(TrainRecord record) {
        record.setId(SnowflakeIdWorker.build().nextId());
        record.setUserId(SecurityUtils.getUserId());
        SysUser sysUser = iSysUserService.selectUserById(SecurityUtils.getUserId());
        record.setDeptId(sysUser.getDeptId());
        ExamQuestionBank bank = iExamQuestionBankService.selectExamQuestionBankById(record.getQuestionId());
        record.setPostId(bank.getPostId());
        record.setType(TrainTypeEnums.SIMULATION.getCode());
        List<SysUserPost> sysUserPosts = iSysUserService.selectPostWithLevel(SecurityUtils.getUserId());
        if (!CollectionUtils.isEmpty(sysUserPosts)) {
            for (SysUserPost sysUserPost : sysUserPosts) {
                if (sysUserPost.getPostId().equals(bank.getPostId())) {
                    record.setPostLevelCode(sysUserPost.getPostLevelCode());
                }
            }
        }
        return trainMapper.insertTrainRecord(record);
    }

    @Override
    public int submitPaper(PaperAnswer answer) {
        long rightAnswerNum = 0, notDoneNum = 0, vagueNum = 0;
        for (PaperAnswer.Answer answerAnswer : answer.getAnswers()) {
            if (answerAnswer.getResult().equals(2L)) {
                rightAnswerNum++;
            } else if (StringUtils.isEmpty(answerAnswer.getContent())) {
                notDoneNum++;
            } else if (!StringUtils.isEmpty(answerAnswer.getContent()) && Objects.isNull(answerAnswer.getResult())) {
                vagueNum++;
            }
            TrainRecord record = answerConverter.answerToTrainRecord(answerAnswer);
            trainMapper.updateTrainRecord(record);
        }
        TrainTestPaper trainTestPaper = new TrainTestPaper();
        trainTestPaper.setId(answer.getPaperId());
        trainTestPaper.setRightAnswerNum(rightAnswerNum);
        trainTestPaper.setNotDoneNum(notDoneNum);
        trainTestPaper.setVagueNum(vagueNum);
        trainTestPaper.setState(TrainTestPaperStateEnums.FINISH.getCode());
        return trainMapper.updateTrainTestPaper(trainTestPaper);
    }

    @Override
    public List<TrainRecord> selectSpecialRecord(Long userId, List<Long> questionIds) {
        return trainMapper.selectSpecialRecord(userId, questionIds);
    }

    @Override
    public Question getSpecialQuestion(SpecialTrainRule rule) {
        SysUser sysUser = iSysUserService.selectUserById(SecurityUtils.getUserId());
        if (Objects.nonNull(rule.getDeptId())) {
            rule.setDeptId(sysUser.getDeptId());
        }
        List<SysUserPost> sysUserPosts = iSysUserService.selectPostWithLevel(SecurityUtils.getUserId());
        String postLevelCode = null;
        for (SysUserPost sysUserPost : sysUserPosts) {
            if (sysUserPost.getPostId().equals(rule.getPostId())) {
                postLevelCode = sysUserPost.getPostLevelCode();
            }
        }
        if (Objects.isNull(postLevelCode)) {
            throw new BaseException("请联系管理员维护当前用户岗位信息");
        }
        // 获取符合要求的试题题目
        List<ExamQuestionBank> examQuestionBanks = listBanksByRule(rule);
        if (examQuestionBanks.isEmpty()) {
            throw new BaseException("请维护相关题库");
        }
        // 获取已经完成过的记录信息
        List<TrainRecord> records = trainMapper.selectLastSpecialRecord(SecurityUtils.getUserId(), examQuestionBanks.stream().map(ExamQuestionBank::getId).toList());
        List<Long> recordIds = records.stream().map(TrainRecord::getId).toList();
        List<Long> questionRecordIds = records.stream().map(TrainRecord::getQuestionId).toList();
        Map<Long, TrainRecord> recordMap = records.stream().collect(Collectors.toMap(TrainRecord::getQuestionId, Function.identity()));
        // 获取未完成的记录
        List<ExamQuestionBank> needTrainQuestions = examQuestionBanks.stream().filter(e -> {
            if (!questionRecordIds.contains(e.getId())) {
                return true;
            } else {
                TrainRecord trainRecord = recordMap.get(e.getId());
                if (Objects.isNull(trainRecord) || ResultTypeEnums.ERROR.getCode().equals(trainRecord.getResult()) || Objects.isNull(trainRecord.getUpdateTime())) {
                    return true;
                }
            }
            return false;
        }).toList();
        ExamQuestionBank examQuestionBank = null;
        if (!needTrainQuestions.isEmpty()) {
            Random random = new Random();
            int randomNumber = random.nextInt(needTrainQuestions.size());
            examQuestionBank = needTrainQuestions.get(randomNumber);
        } else {
            // 随机抽取试题
            Map<String, List<ExamQuestionBank>> postLevelBankMap = examQuestionBanks.stream().collect(Collectors.groupingBy(ExamQuestionBank::getPostLevelCode));
            if (Objects.nonNull(rule.getPostLevelCode())) {
                List<ExamQuestionBank> banks = postLevelBankMap.get(rule.getPostLevelCode());
                if (banks.isEmpty()) {
                    Random random = new Random();
                    int randomNumber = random.nextInt(examQuestionBanks.size());
                    examQuestionBank = examQuestionBanks.get(randomNumber);
                } else {
                    Random random = new Random();
                    int randomNumber = random.nextInt(banks.size());
                    examQuestionBank = banks.get(randomNumber);
                }
            } else {
                Random random = new Random();
                int randomNumber = random.nextInt(examQuestionBanks.size());
                examQuestionBank = examQuestionBanks.get(randomNumber);
            }
        }
        Question question = new Question();
        question.setType(examQuestionBank.getQuestionType());
        question.setQuestionId(examQuestionBank.getId());
        question.setContent(examQuestionBank.getContent());
        question.setRightKey(examQuestionBank.getRightKey());
        List<ExamQuestionBankOption> options = iExamQuestionBankService.listOptionsByBankId(examQuestionBank.getId());
        question.setExamQuestionBankOptionList(options);
        TrainRecord record = new TrainRecord();
        record.setId(SnowflakeIdWorker.build().nextId());
        record.setGrade(question.getGrade());
        record.setQuestionId(question.getQuestionId());
        record.setUserId(SecurityUtils.getUserId());
        record.setType(TrainTypeEnums.SPECIAL.getCode());
        record.setDeptId(sysUser.getDeptId());
        record.setPostId(rule.getPostId());
        record.setPostLevelCode(postLevelCode);
        record.setIsDel(0L);
        question.setRecordId(record.getId());
        question.setAnalysis(examQuestionBank.getAnalysis());
        trainMapper.insertTrainRecord(record);
        return question;
    }

    @Override
    public int answerSpecialQuestion(TrainRecord record) {
        return trainMapper.updateTrainRecord(record);
    }

    @Override
    public List<TrainTestPaper> listUserTrainPaper(TrainTestPaper trainTestPaper) {
        trainTestPaper.setUserId(SecurityUtils.getUserId());
        return listTrainPaper(trainTestPaper);
    }

    @Override
    public List<Question> getPaperDetail(Long id) {
        TrainTestPaper trainTestPaper = trainMapper.selectTrainTestPaperById(id);
        TrainRecord trainRecord = new TrainRecord();
        trainRecord.setTrainSimulationTestPaperId(trainTestPaper.getId());
        List<TrainRecord> records = trainMapper.selectTrainRecordList(trainRecord);
        List<ExamQuestionBank> banks = iExamQuestionBankService.selectExamQuestionBankByIds(records.stream().map(TrainRecord::getQuestionId).toList());
        Map<Long, ExamQuestionBank> bankMap = banks.stream().collect(Collectors.toMap(ExamQuestionBank::getId, Function.identity()));
        List<Question> questions = new ArrayList<>();
        for (TrainRecord e : records) {
            ExamQuestionBank b = bankMap.get(e.getQuestionId());
            Question question = getQuestion(e, b);
            questions.add(question);
        }
        return questions;
    }

    @Override
    public List<TrainRecord> listSpecialRecode(ExamQuestionBank bank) {
        List<ExamQuestionBank> examQuestionBanks = iExamQuestionBankService.selectExamQuestionBankList(bank);
        startPage();
        List<TrainRecord> records = trainMapper.selectSpecialRecord(SecurityUtils.getUserId(), examQuestionBanks.stream().map(ExamQuestionBank::getId).toList());
        List<Long> bankIds = records.stream().map(TrainRecord::getQuestionId).collect(toSet()).stream().toList();
        List<ExamQuestionBank> banks = iExamQuestionBankService.selectExamQuestionBankByIds(bankIds);
        Map<Long, ExamQuestionBank> bankMap = banks.stream().collect(Collectors.toMap(ExamQuestionBank::getId, Function.identity()));
        records.forEach(r -> {
            r.setBank(bankMap.get(r.getQuestionId()));
        });
        return records;
    }

    @Override
    public List<SpecialTrainProgress> specialTrainProgress(Long postId, String postLevelCode) {
        List<ExamQuestionBank> questions = iExamQuestionBankService.listByPost(postId, postLevelCode);
        Map<Long, List<Long>> map = questions.stream().collect(Collectors.groupingBy(ExamQuestionBank::getSubjectId, Collectors.mapping(ExamQuestionBank::getId, toList())));
        List<TrainRecord> records = trainMapper.listSepcialTrainByPost(postId, postLevelCode, SecurityUtils.getUserId());
        List<ExamSubjectKnowledgePoints> examSubjectKnowledgePoints = examSubjectKnowledgePointsService.selectByPostIds(Arrays.asList(postId));
        Map<Long, String> subjectMap = examSubjectKnowledgePoints.stream().collect(Collectors.toMap(ExamSubjectKnowledgePoints::getId, ExamSubjectKnowledgePoints::getName));
        List<SpecialTrainProgress> progresses = new ArrayList<>();
        subjectMap.forEach((k, v) -> {
            SpecialTrainProgress progress = new SpecialTrainProgress();
            progress.setSubjectId(k);
            progress.setSubjectName(v);
            List<Long> banks = map.get(k);
            if (banks == null) {
                return;
            }
            progress.setNum(banks.size());
            List<TrainRecord> trainRecords = records.stream().filter(e -> banks.contains(e.getQuestionId())).distinct().toList();
            progress.setTrainNum(trainRecords.stream().map(TrainRecord::getQuestionId).collect(toSet()).size());
            int rightNum = 0;
            int errorNum = 0;
            int trainQuestionNum = 0;
            Set<Long> trainQuestionIds = new HashSet<>();
            for (TrainRecord trainRecord : trainRecords) {
                if (ResultTypeEnums.RIGHT.getCode().equals(trainRecord.getResult())) {
                    rightNum++;
                } else if (ResultTypeEnums.ERROR.getCode().equals(trainRecord.getResult())) {
                    errorNum++;
                }
                trainQuestionIds.add(trainRecord.getQuestionId());
            }
            trainQuestionNum = trainQuestionIds.size();
            progress.setRightNum(rightNum);
            progress.setErrorNum(errorNum);
            progress.setTrainQuestionNum(trainQuestionNum);
            progresses.add(progress);
        });
        return progresses;
    }

    @Override
    public List<TrainRecord> selectSpecialRecordByDate(LocalDate month) {
        return trainMapper.selectSpecialRecordByDate(SecurityUtils.getUserId(), month);
    }

    @Override
    public List<TrainTestPaper> listUserTrainPaperByDate(LocalDate month) {
        return trainMapper.listUserTrainPaperByDate(SecurityUtils.getUserId(), month);
    }

    @Override
    public List<TrainNum> getTrainNumByMonth() {
        LocalDate now = LocalDate.now();
        LocalDate startDate = now.minusMonths(1);
        List<TrainNum> trainNumByMonth = trainMapper.getTrainNumByMonth(SecurityUtils.getUserId(), startDate, now);
        Map<LocalDate, Integer> map = trainNumByMonth.stream().collect(Collectors.toMap(TrainNum::getDate, TrainNum::getNum));
        List<TrainNum> trainNums = new ArrayList<>();
        while (!startDate.isAfter(now)) {
            TrainNum trainNum = new TrainNum();
            trainNum.setDate(startDate);
            Integer i = map.get(startDate);
            if (Objects.isNull(i)) {
                trainNum.setNum(0);
            } else {
                trainNum.setNum(i);
            }
            trainNums.add(trainNum);
            startDate = startDate.plusDays(1);
        }
        return trainNums;
    }

    @Override
    public List<SubjectAnalysis> getTrainSubjectAnalysis() {
        // 获取用户所有岗位
        List<SysUserPost> sysUserPosts = iSysUserService.selectPostWithLevel(SecurityUtils.getUserId());
        if (sysUserPosts.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> postIds = sysUserPosts.stream().map(SysUserPost::getPostId).toList();
        List<ExamSubjectKnowledgePoints> examSubjectKnowledgePoints = examSubjectKnowledgePointsService.selectByPostIds(postIds);
        if (examSubjectKnowledgePoints.isEmpty()) {
            return Collections.emptyList();
        }
        List<TrainRecord> trainRecords = trainMapper.selectSpecialRecordByUser(SecurityUtils.getUserId());
        Map<Long, List<TrainRecord>> map;
        if (!trainRecords.isEmpty()) {
            List<ExamQuestionBank> banks = iExamQuestionBankService.selectExamQuestionBankByIds(trainRecords.stream().map(TrainRecord::getQuestionId).collect(toSet()).stream().toList());
            Map<Long, Long> bankMap = banks.stream().collect(toMap(ExamQuestionBank::getId, ExamQuestionBank::getSubjectId));
            map = trainRecords.stream().collect(Collectors.groupingBy(record -> bankMap.get(record.getQuestionId())));
        } else {
            map = new HashMap<>();
        }
        List<SubjectAnalysis> analyses = new ArrayList<>();
        examSubjectKnowledgePoints.forEach(e -> {
            SubjectAnalysis subjectAnalysis = new SubjectAnalysis();
            analyses.add(subjectAnalysis);
            subjectAnalysis.setSubjectId(e.getId());
            subjectAnalysis.setSubjectName(e.getName());
            List<TrainRecord> records = map.get(e.getId());
            if (CollectionUtils.isEmpty(records)) {
                subjectAnalysis.setNum(0);
                subjectAnalysis.setRightNum(0);
                return;
            }
            subjectAnalysis.setNum(records.size());
            long count = records.stream().filter(r -> ResultTypeEnums.RIGHT.getCode().equals(r.getResult())).count();
            subjectAnalysis.setRightNum((int) count);
        });
        return analyses;
    }

    @Override
    public SpecialTrainProgress getTrainNumAndErrorNum(StatisticalParam statisticalParam) {
        //  查询训练题目
        List<TrainRecord> recordList = trainMapper.selectTrainRecordByTime(statisticalParam);
        // 组装数据
        SpecialTrainProgress progress = new SpecialTrainProgress();
        if (!ObjectUtils.isEmpty(recordList)) {
            progress.setNum(recordList.size());
            progress.setErrorNum((int) recordList.stream().filter(re -> re.getResult() != null && Objects.equals(re.getResult(), ResultTypeEnums.ERROR.getCode())).count());
            progress.setRightNum((int) recordList.stream().filter(re -> re.getResult() != null && Objects.equals(re.getResult(), ResultTypeEnums.RIGHT.getCode())).count());
        }
        return progress;
    }

    @Override
    public List<UserRankingParam> userRanking(UserRankingParam param) {
        // 查询符合条件的训练数据
        TrainRecord record = new TrainRecord();
        record.setUserId(param.getUserId());
        record.setPostId(param.getPostId());
        record.setPostLevelCode(param.getPostLevelCode());
        List<TrainRecord> records = trainMapper.selectTrainRecordList(record);
        List<UserRankingParam> userRankingParams = new ArrayList<>(records.size());
        // 组装数据
        if (!ObjectUtils.isEmpty(records)) {
            Map<Long, List<TrainRecord>> recordMap = records.stream().collect(groupingBy(TrainRecord::getUserId));
            recordMap.forEach((k, v) -> {
                UserRankingParam rank = new UserRankingParam();
                rank.setUserId(k);
                rank.setPostId(v.get(0).getPostId());
                rank.setPostLevelCode(v.get(0).getPostLevelCode());
                rank.setNum(v.size());
                rank.setErrorNum((int) v.stream().filter(r -> r.getResult() != null && ResultTypeEnums.ERROR.getCode().equals(r.getResult())).count());
                rank.setErrorRate((double) rank.getErrorNum() / rank.getNum());
                userRankingParams.add(rank);
            });
        }
        return userRankingParams;
    }

    @Override
    public List<CommonTemplatesVo> commonTemplates() {
        // 查询常用的模板和使用数量
        List<CommonTemplatesVo> commonTemplatesVos = trainMapper.selectCountAndModuleId();
        if (!ObjectUtils.isEmpty(commonTemplatesVos)) {
            List<Long> moduleIds = commonTemplatesVos.stream().map(CommonTemplatesVo::getModuleId).toList();
            List<ExamTestPaperModule> examTestPaperModules = iExamTestPaperModuleService.selectExamTestPaperModuleByIds(moduleIds);
            Map<Long, String> moduleNameMap = examTestPaperModules.stream().collect(toMap(ExamTestPaperModule::getId, ExamTestPaperModule::getName));
            // 查询已完成的训练试卷
            List<TrainTestPaper> testPapers = trainMapper.selectTrainPaperByModuleIds(moduleIds);
            Map<Long, List<TrainTestPaper>> moduleMap = testPapers.stream().collect(groupingBy(TrainTestPaper::getTestPaperModuleId));
            commonTemplatesVos.forEach(vo -> {
                int errorNum = 0;
                int count = 0;
                List<TrainTestPaper> papers = moduleMap.get(vo.getModuleId());
                for (TrainTestPaper p : papers) {
                    errorNum += p.getQuestionNum() - p.getRightAnswerNum();
                    count += p.getQuestionNum();
                }
                vo.setModuleName(moduleNameMap.get(vo.getModuleId()));
                vo.setErrorNum(errorNum);
                vo.setErrorRate((double) errorNum / count);
            });
        }
        return commonTemplatesVos;
    }

    @Override
    public Map<String, Integer> errorProportion() {
        Map<String, Integer> map = new HashMap<>();
        Double rate = 0.0;
        // 查询训练完成的试卷
        TrainTestPaper train = new TrainTestPaper();
        train.setState(TrainTestPaperStateEnums.FINISH.getCode());
        train.setIsDel(0L);
        List<TrainTestPaper> trainTestPaperList = trainMapper.selectTrainTestPaperList(train);
        if (!ObjectUtils.isEmpty(trainTestPaperList)) {
            int errorNum = 0;
            int countNum = 0;
            for (TrainTestPaper paper : trainTestPaperList) {
                errorNum += paper.getQuestionNum() - paper.getRightAnswerNum();
                countNum += paper.getQuestionNum();
            }
            map.put("all", countNum);
            map.put("error", errorNum);
            rate = (double) errorNum / countNum;
        }
        return map;
    }

    @Override
    public List<TrainTestPaper> paperList(TrainTestPaper trainTestPaper) {
        return listTrainPaper(trainTestPaper);
    }

    /**
     * 将获取
     * 【岗位】【科目】【知识点】训练数量
     * 【岗位】【科目】【知识点】训练错误数量
     *
     * @param userId
     * @param startDate
     * @param endDate
     * @return
     */
    @Override
    public Map<String, List<SunriseChartData>> getSunriseChartData(Long userId, LocalDate startDate, LocalDate endDate) {
        Map<String, List<SunriseChartData>> map = new HashMap<>();
        List<SunriseChartData> all = new ArrayList<>();
        List<SunriseChartData> error = new ArrayList<>();
        map.put("all", all);
        map.put("error", error);
        List<TrainRecord> records = trainMapper.selectSpecialRecordByCondition(userId, startDate, endDate);
        if (records.isEmpty()) {
            return map;
        }
        ExamSubjectKnowledgePoints knowledgePoints = new ExamSubjectKnowledgePoints();
        knowledgePoints.setIsDel(0L);
        List<ExamSubjectKnowledgePoints> examSubjectKnowledgePoints = examSubjectKnowledgePointsService.selectExamSubjectKnowledgePointsList(knowledgePoints);
        List<ExamSubjectKnowledgePoints> subject = examSubjectKnowledgePoints.stream().filter(e -> Objects.nonNull(e.getPostId())).toList();
        List<Long> postIds = subject.stream().map(ExamSubjectKnowledgePoints::getPostId).collect(toSet()).stream().toList();
        Map<Long, List<ExamSubjectKnowledgePoints>> postSubjectMap = subject.stream().collect(groupingBy(ExamSubjectKnowledgePoints::getPostId));
        Map<Long, List<ExamSubjectKnowledgePoints>> subjectKnowMap = examSubjectKnowledgePoints.stream().filter(e -> Objects.nonNull(e.getSubjectId()))
                .collect(groupingBy(ExamSubjectKnowledgePoints::getSubjectId));

        List<SysPost> sysPosts = sysPostService.selectPostAll();
        Map<Long, String> postMap = sysPosts.stream().collect(toMap(SysPost::getPostId, SysPost::getPostName));
        List<ExamQuestionBank> banks = iExamQuestionBankService.selectExamQuestionBankByIds(records.stream().map(TrainRecord::getQuestionId).collect(toSet()).stream().toList());
        Map<Long, ExamQuestionBank> bankMap = banks.stream().collect(toMap(ExamQuestionBank::getId, Function.identity()));
        Map<String, Integer> allRecord = new HashMap<>();
        Map<String, Integer> errorRecord = new HashMap<>();
        for (TrainRecord e : records) {
            ExamQuestionBank bank = bankMap.get(e.getQuestionId());
            if (ObjectUtils.isEmpty(bank)) {
                break;
            }
            Integer postAllRecord = allRecord.get(bank.getPostId() + "post");
            Integer subjectAllRecord = allRecord.get(bank.getSubjectId() + "subject");
            Integer knowAllRecord = allRecord.get(bank.getKnowledgePointsId() + "know");
            postAllRecord = postAllRecord == null ? 1 : postAllRecord + 1;
            subjectAllRecord = subjectAllRecord == null ? 1 : subjectAllRecord + 1;
            knowAllRecord = knowAllRecord == null ? 1 : knowAllRecord + 1;
            allRecord.put(bank.getPostId() + "post", postAllRecord);
            allRecord.put(bank.getSubjectId() + "subject", subjectAllRecord);
            allRecord.put(bank.getKnowledgePointsId() + "know", knowAllRecord);

            if (ResultTypeEnums.ERROR.getCode().equals(e.getResult())) {
                Integer postErrRecord = errorRecord.get(bank.getPostId() + "post");
                Integer subjectErrRecord = errorRecord.get(bank.getSubjectId() + "subject");
                Integer knowErrRecord = errorRecord.get(bank.getKnowledgePointsId() + "know");
                postErrRecord = postErrRecord == null ? 1 : postErrRecord + 1;
                subjectErrRecord = subjectErrRecord == null ? 1 : subjectErrRecord + 1;
                knowErrRecord = knowErrRecord == null ? 1 : knowErrRecord + 1;
                errorRecord.put(bank.getPostId() + "post", postErrRecord);
                errorRecord.put(bank.getSubjectId() + "subject", subjectErrRecord);
                errorRecord.put(bank.getKnowledgePointsId() + "know", knowErrRecord);
            }
        }
        postIds.forEach(e -> {
            List<ExamSubjectKnowledgePoints> pointIds = postSubjectMap.get(e);
            SunriseChartData allData = new SunriseChartData();
            allData.setId(e);
            allData.setType(0);
            allData.setName(postMap.get(e));
            allData.setValue(allRecord.get(e + "post"));
            all.add(allData);
            SunriseChartData errorData = new SunriseChartData();
            errorData.setId(e);
            errorData.setType(0);
            errorData.setName(postMap.get(e));
            errorData.setValue(errorRecord.get(e + "post"));
            error.add(errorData);
            // 设置科目
            if (pointIds.isEmpty()) {
                return;
            }
            List<SunriseChartData> subjectAllChildren = new ArrayList<>();
            List<SunriseChartData> subjectErrChildren = new ArrayList<>();
            allData.setChildren(subjectAllChildren);
            errorData.setChildren(subjectErrChildren);
            pointIds.forEach(s -> {
                SunriseChartData subjectAllData = new SunriseChartData();
                subjectAllData.setId(s.getId());
                subjectAllData.setType(1);
                subjectAllData.setName(s.getName());
                subjectAllData.setValue(allRecord.get(s.getId() + "subject"));
                subjectAllChildren.add(subjectAllData);
                SunriseChartData subjectErrData = new SunriseChartData();
                subjectErrData.setId(s.getId());
                subjectErrData.setType(1);
                subjectErrData.setName(s.getName());
                subjectErrData.setValue(errorRecord.get(s.getId() + "subject"));
                subjectErrChildren.add(subjectErrData);
                List<ExamSubjectKnowledgePoints> knows = subjectKnowMap.get(s.getId());
                if (knows.isEmpty()) {
                    return;
                }
                List<SunriseChartData> knowAllChildren = new ArrayList<>();
                List<SunriseChartData> knowErrChildren = new ArrayList<>();
                subjectAllData.setChildren(knowAllChildren);
                subjectErrData.setChildren(knowErrChildren);
                knows.forEach(k -> {
                    SunriseChartData knowAllData = new SunriseChartData();
                    knowAllData.setId(k.getId());
                    knowAllData.setType(2);
                    knowAllData.setName(k.getName());
                    knowAllData.setValue(allRecord.get(k.getId() + "know"));
                    knowAllChildren.add(knowAllData);
                    SunriseChartData knowErrData = new SunriseChartData();
                    knowErrData.setId(k.getId());
                    knowErrData.setType(2);
                    knowErrData.setName(k.getName());
                    knowErrData.setValue(errorRecord.get(k.getId() + "know"));
                    knowErrChildren.add(knowErrData);
                });
            });
        });
        return map;
    }

    @Override
    public LineChartData<LocalDate, Integer> getTrainLineChart(Long userId, LocalDate startDate, LocalDate endDate) {
        LineChartData<LocalDate, Integer> data = new LineChartData<>();
        List<LocalDate> xdatas = new ArrayList<>();
        List<Integer> ydatas = new ArrayList<>();
        List<Integer> ydatas1 = new ArrayList<>();
        data.setXdatas(xdatas);
        data.setYdatas(ydatas);
        data.setYdatas1(ydatas1);
        if (Objects.isNull(startDate)) {
            if (Objects.isNull(endDate)) {
                endDate = LocalDate.now();
            }
            startDate = endDate.minusMonths(1);
        }
        if (Objects.isNull(endDate)) {
            endDate = startDate.plusMonths(1);
        }
        List<TrainRecord> records = trainMapper.selectSpecialRecordByCondition(userId, startDate, endDate);
        Map<LocalDate, List<TrainRecord>> recordMap = records.stream().collect(groupingBy(record -> record.getCreateTime().toLocalDate()));
        LocalDate date = startDate;
        while (!date.isAfter(endDate)) {
            xdatas.add(date);
            List<TrainRecord> rs = recordMap.get(date);
            if (Objects.isNull(rs)) {
                ydatas.add(0);
                ydatas1.add(0);
            } else {
                ydatas.add(rs.size());
                ydatas1.add((int) rs.stream().filter(r -> ResultTypeEnums.ERROR.getCode().equals(r.getResult())).count());
            }
            date = date.plusDays(1);

        }
        return data;
    }

    @NotNull
    private static Question getQuestion(TrainRecord e, ExamQuestionBank b) {
        Question question = new Question();
        question.setRecordId(e.getId());
        question.setQuestionId(b.getId());
        question.setGrade(e.getGrade());
        question.setResult(e.getResult());
        question.setResultContent(e.getContent());
        question.setGainGrade(e.getGainGrade());
        question.setType(b.getQuestionType());
        question.setAnalysis(b.getAnalysis());
        question.setContent(b.getContent());
        question.setRightKey(b.getRightKey());
        question.setExamQuestionBankOptionList(b.getExamQuestionBankOptionList());
        return question;
    }

    private List<TrainTestPaper> listTrainPaper(TrainTestPaper trainTestPaper) {
        List<TrainTestPaper> testPapers = trainMapper.selectTrainTestPaperList(trainTestPaper);
        if (testPapers.isEmpty()) {
            return Collections.emptyList();
        }
        List<Long> moduleIds = testPapers.stream().map(TrainTestPaper::getTestPaperModuleId).collect(toSet()).stream().toList();
        List<ExamTestPaperModule> modules = iExamTestPaperModuleService.selectExamTestPaperModuleByIds(moduleIds);
        Map<Long, String> moduleMap = modules.stream().collect(Collectors.toMap(ExamTestPaperModule::getId, ExamTestPaperModule::getName));
        List<Long> deptIds = testPapers.stream().map(TrainTestPaper::getDeptId).collect(toSet()).stream().toList();
        List<SysDept> depts = iSysDeptService.selectDeptByIds(deptIds);
        Map<Long, String> deptMap = depts.stream().collect(Collectors.toMap(SysDept::getDeptId, SysDept::getDeptName));
        List<Long> postIds = testPapers.stream().map(TrainTestPaper::getPostId).collect(toSet()).stream().toList();
        List<SysPost> posts = sysPostService.selectPostListByIds(postIds);
        Map<Long, String> postMap = posts.stream().collect(Collectors.toMap(SysPost::getPostId, SysPost::getPostName));
        testPapers.forEach(e -> {
            e.setTestPaperModuleName(moduleMap.get(e.getTestPaperModuleId()));
            e.setPostName(postMap.get(e.getPostId()));
            e.setDeptName(deptMap.get(e.getDeptId()));
        });
        return testPapers;
    }

    private List<ExamQuestionBank> listBanksByRule(SpecialTrainRule rule) {
        ExamQuestionBank bank = new ExamQuestionBank();
        bank.setIsDel(0L);
        bank.setDeptId(rule.getDeptId());
        bank.setSyllabusCode(rule.getSyllabusCode());
        bank.setPostId(rule.getPostId());
        bank.setPostLevelCode(rule.getPostLevelCode());
        bank.setSubjectId(rule.getSubjectId());
        bank.setKnowledgePointsId(rule.getKnowledgePointId());
        List<ExamQuestionBank> examQuestionBanks = iExamQuestionBankService.selectExamQuestionBankList(bank);
        return examQuestionBanks;
    }

    private void QuestionToRecord(List<Question> questions, Long type, Long postId, TrainTestPaper testPaper) {
        SysUser sysUser = iSysUserService.selectUserById(SecurityUtils.getUserId());
        if (!testPaper.getDeptId().equals(sysUser.getDeptId())) {
            throw new BaseException("该用户所在部门不能进行该模板模拟训练");
        }
        List<SysUserPost> sysUserPosts = iSysUserService.selectPostWithLevel(SecurityUtils.getUserId());
        String postLevelCode = null;
        for (SysUserPost sysUserPost : sysUserPosts) {
            if (sysUserPost.getPostId().equals(postId)) {
                postLevelCode = sysUserPost.getPostLevelCode();
            }
        }
        if (Objects.isNull(postLevelCode)) {
            throw new BaseException("该用户岗位不能进行该模拟训练考试");
        }
        if (Objects.nonNull(testPaper)) {
            testPaper.setPostId(postId);
            testPaper.setPostLevelCode(postLevelCode);
        } else {
            testPaper = new TrainTestPaper();
        }
        List<TrainRecord> records = new ArrayList<>();
        for (Question e : questions) {
            TrainRecord record = new TrainRecord();
            record.setId(SnowflakeIdWorker.build().nextId());
            record.setGrade(e.getGrade());
            record.setQuestionId(e.getQuestionId());
            record.setUserId(SecurityUtils.getUserId());
            record.setType(type);
            record.setDeptId(sysUser.getDeptId());
            record.setPostId(postId);
            record.setTrainSimulationTestPaperId(testPaper.getId());
            record.setPostLevelCode(postLevelCode);
            record.setIsDel(0L);
            records.add(record);
            e.setRecordId(record.getId());
        }
        trainMapper.batchTrainRecord(records);
    }
}
